package ru.papergames.battleserver.model.battle.map;

import ru.common.util.Point3D;
import ru.papergames.battleserver.model.battle.BallColor;
import ru.papergames.battleserver.model.battle.GameBall;

import java.util.*;

/**
 * @author: atroshanin
 * Date: 11.04.2010
 * Time: 18:32:49
 */
public class BattleMap {

    private int width;
    private int height;

    private List<Obstacle> obstacles;

    /**
     * FIrst    [] is X coordinate,
     * Second   [] is Y coordinate,
     */
    private Cell[][] cells;
    private int [] freeCellsCountPerColumn;
    private int freeCellsCount;

    private Map<BallColor, Set<GameBall>> gameBallsByColors;

    public BattleMap(int width, int height) {
        this.width = width;
        this.height = height;
        cells = new Cell[width][height];
        for (int x = 0; x < cells.length; x++) {
            for (int y = 0; y < cells[x].length; y++) {
                cells[x][y] = new Cell(x, y);
            }
        }
        freeCellsCountPerColumn = new int[width];
        for (int i=0; i<freeCellsCountPerColumn.length; i++) {
            freeCellsCountPerColumn[i] = height;
        }
        freeCellsCount = width * height;

        gameBallsByColors = new HashMap<BallColor, Set<GameBall>>();
        for (BallColor color : BallColor.values()) {
            gameBallsByColors.put(color, new HashSet<GameBall>());
        }
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    public int[] getFreeCellsCountPerColumn() {
        return freeCellsCountPerColumn;
    }

    public void addObstacle(Obstacle obstacle) {
        if (obstacles == null) {
            obstacles = new LinkedList<Obstacle>();
        }
        obstacles.add(obstacle);

        int leftUpConnerX = obstacle.getLeftUpConnerX();
        int leftUpConnerY = obstacle.getLeftUpConnerY();
        for (Obstacle.BlockedCell blockedCell : obstacle.getBlockedCells()) {
            Cell cell = getCell(leftUpConnerX + blockedCell.getX(), leftUpConnerY + blockedCell.getY());
            if (cell != null) {
                cell.setState(CellState.BUSY_WITH_OBSTACLE);
                cell.setObstacle(obstacle);

                int x = cell.getX();
                freeCellsCountPerColumn[x] = freeCellsCountPerColumn[x] - 1;
                freeCellsCount--;
            }
        }

//        obstacle.blockCellsOnMap(this);
    }

    public List<Obstacle> getObstacles() {
        return obstacles;
    }

    public GameBall getGameBall(Point3D point) {
        Cell cell = getCell(point.getX(), point.getY());
        return cell != null ? cell.getGameBall() : null;
    }

    public Cell getCell(Point3D point) {
        return getCell(point.getX(), point.getY());
    }

    public GameBall getGameBall(int x, int y) {
        Cell cell = getCell(x, y);
        return cell != null ? cell.getGameBall() : null;
    }

    public Cell getCell(int x, int y) {
        return (x >= 0 && x < width && y >= 0 && y < height) ? cells[x][y] : null;
    }

    public float getCost(int sx, int sy, int tx, int ty) {
        return sx - tx == 0 || sy - ty == 0 ? 10 : 14;
    }

    public boolean isCellFree(Point3D point) {
        Cell cell = getCell(point);
        return cell != null && cell.getGameBall() == null && cell.getObstacle() == null;
    }

    public void addNewGameBall(Cell cell, GameBall ball) {
        addGameBallToCell(cell, ball);
        gameBallsByColors.get(ball.getColor()).add(ball);
    }

    public void removeGameBall(Cell cell) {
        GameBall ball = cell.getGameBall();
        removeGameBallFromCell(cell);
        gameBallsByColors.get(ball.getColor()).remove(ball);
    }

    private void addGameBallToCell(Cell cell, GameBall ball) {
        cell.setGameBall(ball);
        int x = cell.getX();
        freeCellsCountPerColumn[x] = freeCellsCountPerColumn[x] - 1;
        freeCellsCount--;
    }

    private void removeGameBallFromCell(Cell cell) {
        cell.removeGameBall();
        int x = cell.getX();
        freeCellsCountPerColumn[x] = freeCellsCountPerColumn[x] + 1;
        freeCellsCount++;
    }

    public void moveGameBall(Point3D srcPoint, Point3D dstPoint) {
        Cell srcCell = getCell(srcPoint);
        Cell dstCell = getCell(dstPoint);
        GameBall ball = srcCell.getGameBall();
        removeGameBallFromCell(srcCell);
        addGameBallToCell(dstCell, ball);
    }

    public int getFreeCellsCount() {
        return freeCellsCount;
    }

    public Set<GameBall> getBallsOfColor(BallColor color) {
        return gameBallsByColors.get(color);
    }
}
